1   /*
2    * Copyright (c) 2007, 2008, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.
8    *
9    * This code is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12   * version 2 for more details (a copy is included in the LICENSE file that
13   * accompanied this code).
14   *
15   * You should have received a copy of the GNU General Public License version
16   * 2 along with this work; if not, write to the Free Software Foundation,
17   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18   *
19   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20   * or visit www.oracle.com if you need additional information or have any
21   * questions.
22   */
23  
24  /* @test
25   *
26   * @bug 6608456
27   * @author Igor Kushnirskiy
28   * @summary tests if delegate RepaintManager gets invoked.
29   */
30  
31  import java.awt.*;
32  import java.lang.reflect.Method;
33  import java.util.concurrent.Callable;
34  import java.util.concurrent.FutureTask;
35  import java.util.concurrent.TimeUnit;
36  
37  import javax.swing.JComponent;
38  import javax.swing.JButton;
39  import javax.swing.JFrame;
40  import javax.swing.RepaintManager;
41  import javax.swing.SwingUtilities;
42  
43  
44  
45  public class bug6608456 {
46      private static final TestFuture testFuture = new TestFuture();
47      public static void main(String[] args) throws Exception {
48          final JComponent component = invokeAndWait(
49              new Callable<JComponent>() {
50                  public JComponent call() throws Exception {
51                      RepaintManager.setCurrentManager(new TestRepaintManager());
52                      JFrame frame = new JFrame("test");
53                      frame.setLayout(new FlowLayout());
54                      JButton button = new JButton("default");
55  
56                      frame.add(button);
57                      button = new JButton("delegate");
58                      if ( ! registerDelegate(
59                               button, new TestRepaintManager())) {
60                          return null;
61                      }
62                      frame.add(button);
63                      frame.pack();
64                      frame.setVisible(true);
65                      return button;
66                  }
67              });
68          if (component == null) {
69              throw new RuntimeException("failed. can not register delegate");
70          }
71          blockTillDisplayed(component);
72          // trigger repaint for delegate RepaintManager
73          invokeAndWait(
74              new Callable<Void>() {
75                  public Void call() {
76                      component.repaint();
77                      return null;
78                  }
79          });
80          try {
81              if (testFuture.get(10, TimeUnit.SECONDS)) {
82                  // passed
83              }
84          } catch (Exception e) {
85              throw new RuntimeException("failed", e);
86          } finally {
87              JFrame frame = (JFrame) SwingUtilities
88                  .getAncestorOfClass(JFrame.class, component);
89              if (frame != null) {
90                  frame.dispose();
91              }
92          }
93      }
94      static class TestRepaintManager extends RepaintManager {
95          @Override
96          public void addDirtyRegion(JComponent c, int x, int y, int w, int h) {
97              if (RepaintManager.currentManager(c) == this) {
98                  testFuture.defaultCalled();
99              } else {
100                 testFuture.delegateCalled();
101             }
102             super.addDirtyRegion(c, x, y, w, h);
103         }
104     }
105     static class TestFuture extends FutureTask<Boolean> {
106         private volatile boolean defaultCalled = false;
107         private volatile boolean delegateCalled = false;
108         public TestFuture() {
109             super(new Callable<Boolean>() {
110                 public Boolean call() {
111                     return null;
112                 }
113             });
114         }
115         public void defaultCalled() {
116             defaultCalled = true;
117             updateState();
118         }
119         public void delegateCalled() {
120             delegateCalled = true;
121             updateState();
122         }
123         private void updateState() {
124             if (defaultCalled && delegateCalled) {
125                 set(Boolean.TRUE);
126             }
127         }
128     }
129 
130     private static boolean registerDelegate(JComponent c,
131             RepaintManager repaintManager) {
132         boolean rv = false;
133         try {
134             Class<?> clazz = Class.forName("com.sun.java.swing.SwingUtilities3");
135             Method method = clazz.getMethod("setDelegateRepaintManager",
136                 JComponent.class, RepaintManager.class);
137             method.invoke(clazz, c, repaintManager);
138             rv = true;
139         } catch (Exception ignore) {
140         }
141         return rv;
142     }
143     static <T> T invokeAndWait(Callable<T> callable) throws Exception {
144         FutureTask<T> future = new FutureTask<T>(callable);
145         SwingUtilities.invokeLater(future);
146         return future.get();
147     }
148 
149     public static void blockTillDisplayed(Component comp) {
150         Point p = null;
151         while (p == null) {
152             try {
153                 p = comp.getLocationOnScreen();
154             } catch (IllegalStateException e) {
155                 try {
156                     Thread.sleep(100);
157                 } catch (InterruptedException ie) {
158                 }
159             }
160         }
161     }
162 }